{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "9d250120-5609-4649-8a2d-4693614a7577",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "数据生成完成！已保存至 data 目录。\n"
     ]
    }
   ],
   "source": [
    "from faker import Faker\n",
    "import pandas as pd\n",
    "from datetime import datetime, timedelta\n",
    "import random\n",
    "import os\n",
    "\n",
    "# 初始化Faker（中文环境）\n",
    "fake = Faker('zh_CN')\n",
    "\n",
    "# ===================== 1. 生成用户数据 =====================\n",
    "def generate_users(n=1000):\n",
    "    users = []\n",
    "    for i in range(n):\n",
    "        user = {\n",
    "            'user_id': i + 1,\n",
    "            'name': fake.name(),\n",
    "            'gender': random.choice(['男', '女']),\n",
    "            'age': random.randint(18, 60),\n",
    "            'city': fake.city(),\n",
    "            'register_time': fake.date_time_between(start_date='-3y', end_date='now')\n",
    "        }\n",
    "        users.append(user)\n",
    "    return pd.DataFrame(users)\n",
    "\n",
    "# ===================== 2. 生成商品数据 =====================\n",
    "def generate_products(n=200):\n",
    "    products = []\n",
    "    categories = ['电子产品', '服装', '家居', '食品', '图书']\n",
    "    for i in range(n):\n",
    "        product = {\n",
    "            'product_id': i + 1,\n",
    "            'product_name': fake.word() + '产品',\n",
    "            'category': random.choice(categories),\n",
    "            'price': round(random.uniform(10, 1000), 2)\n",
    "        }\n",
    "        products.append(product)\n",
    "    return pd.DataFrame(products)\n",
    "\n",
    "# ===================== 3. 生成订单数据（关联用户和商品） =====================\n",
    "def generate_orders(users_df, products_df, n=5000):\n",
    "    orders = []\n",
    "    for i in range(n):\n",
    "        user_id = random.choice(users_df['user_id'].tolist())\n",
    "        product_id = random.choice(products_df['product_id'].tolist())\n",
    "        price = products_df[products_df['product_id'] == product_id]['price'].values[0]\n",
    "        quantity = random.randint(1, 5)\n",
    "        orders.append({\n",
    "            'order_id': i + 1,\n",
    "            'user_id': user_id,\n",
    "            'product_id': product_id,\n",
    "            'order_time': fake.date_time_between(start_date='-1y', end_date='now'),\n",
    "            'quantity': quantity,\n",
    "            'amount': round(price * quantity, 2)\n",
    "        })\n",
    "    return pd.DataFrame(orders)\n",
    "\n",
    "# ===================== 4. 执行生成并导出数据 =====================\n",
    "if __name__ == \"__main__\":\n",
    "    # 创建数据目录\n",
    "    os.makedirs('../data', exist_ok=True)\n",
    "    \n",
    "    # 生成数据\n",
    "    users_df = generate_users(1000)\n",
    "    products_df = generate_products(200)\n",
    "    orders_df = generate_orders(users_df, products_df, 5000)\n",
    "    \n",
    "    # 导出为CSV\n",
    "    users_df.to_csv('../data/users.csv', index=False)\n",
    "    products_df.to_csv('../data/products.csv', index=False)\n",
    "    orders_df.to_csv('../data/orders.csv', index=False)\n",
    "    \n",
    "    # 导出为SQLite（可选）\n",
    "    from sqlalchemy import create_engine\n",
    "    engine = create_engine('sqlite:///../data/ecommerce.db')\n",
    "    users_df.to_sql('users', engine, if_exists='replace', index=False)\n",
    "    products_df.to_sql('products', engine, if_exists='replace', index=False)\n",
    "    orders_df.to_sql('orders', engine, if_exists='replace', index=False)\n",
    "    \n",
    "    print(\"数据生成完成！已保存至 data 目录。\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "9fb53e82-bb16-4202-9322-dc181c67a599",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 26376 (\\N{CJK UNIFIED IDEOGRAPH-6708}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 20221 (\\N{CJK UNIFIED IDEOGRAPH-4EFD}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 38144 (\\N{CJK UNIFIED IDEOGRAPH-9500}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 21806 (\\N{CJK UNIFIED IDEOGRAPH-552E}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 39069 (\\N{CJK UNIFIED IDEOGRAPH-989D}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 65288 (\\N{FULLWIDTH LEFT PARENTHESIS}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 20803 (\\N{CJK UNIFIED IDEOGRAPH-5143}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 65289 (\\N{FULLWIDTH RIGHT PARENTHESIS}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 24230 (\\N{CJK UNIFIED IDEOGRAPH-5EA6}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 36235 (\\N{CJK UNIFIED IDEOGRAPH-8D8B}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:31: UserWarning:\n",
      "\n",
      "Glyph 21183 (\\N{CJK UNIFIED IDEOGRAPH-52BF}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 38144 (\\N{CJK UNIFIED IDEOGRAPH-9500}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 21806 (\\N{CJK UNIFIED IDEOGRAPH-552E}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 39069 (\\N{CJK UNIFIED IDEOGRAPH-989D}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 65288 (\\N{FULLWIDTH LEFT PARENTHESIS}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 20803 (\\N{CJK UNIFIED IDEOGRAPH-5143}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 65289 (\\N{FULLWIDTH RIGHT PARENTHESIS}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 26376 (\\N{CJK UNIFIED IDEOGRAPH-6708}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 24230 (\\N{CJK UNIFIED IDEOGRAPH-5EA6}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 36235 (\\N{CJK UNIFIED IDEOGRAPH-8D8B}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 21183 (\\N{CJK UNIFIED IDEOGRAPH-52BF}) missing from current font.\n",
      "\n",
      "C:\\Users\\LENOVO\\AppData\\Local\\Temp\\ipykernel_25448\\3955488609.py:35: UserWarning:\n",
      "\n",
      "Glyph 20221 (\\N{CJK UNIFIED IDEOGRAPH-4EFD}) missing from current font.\n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "销售趋势折线图已保存。\n",
      "用户地域分布地图已保存（HTML交互式图表）。\n",
      "所有可视化任务完成！结果已保存至 visualizations 目录。\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from pyecharts import options as opts\n",
    "from pyecharts.charts import Map\n",
    "import plotly.express as px\n",
    "import os\n",
    "\n",
    "# ===================== 1. 加载数据 =====================\n",
    "users_df = pd.read_csv('../data/users.csv')\n",
    "products_df = pd.read_csv('../data/products.csv')\n",
    "orders_df = pd.read_csv('../data/orders.csv')\n",
    "orders_df['order_time'] = pd.to_datetime(orders_df['order_time'])\n",
    "\n",
    "\n",
    "# ===================== 模板1：销售趋势折线图 =====================\n",
    "def plot_sales_trend():\n",
    "    # 按月份聚合销售额\n",
    "    orders_df['month'] = orders_df['order_time'].dt.to_period('M')\n",
    "    monthly_sales = orders_df.groupby('month')['amount'].sum().reset_index()\n",
    "    monthly_sales['month'] = monthly_sales['month'].dt.to_timestamp()  # 转换为datetime格式\n",
    "    \n",
    "    # 绘图\n",
    "    plt.figure(figsize=(12, 6))\n",
    "    sns.lineplot(x='month', y='amount', data=monthly_sales, marker='o', color='#2F5496')\n",
    "    plt.title('月度销售趋势', fontsize=16)\n",
    "    plt.xlabel('月份', fontsize=12)\n",
    "    plt.ylabel('销售额（元）', fontsize=12)\n",
    "    plt.grid(True, linestyle='--', alpha=0.7)\n",
    "    plt.xticks(rotation=45)\n",
    "    plt.tight_layout()\n",
    "    \n",
    "    # 保存\n",
    "    os.makedirs('../visualizations', exist_ok=True)\n",
    "    plt.savefig('../visualizations/sales_trend.png', dpi=300)\n",
    "    plt.close()\n",
    "    print(\"销售趋势折线图已保存。\")\n",
    "\n",
    "\n",
    "# ===================== 模板2：用户地域分布地图 =====================\n",
    "def plot_user_map():\n",
    "    # 处理城市名称（适配Pyecharts地图）\n",
    "    users_df['city'] = users_df['city'].str.replace('市', '')\n",
    "    city_counts = users_df['city'].value_counts().reset_index()\n",
    "    city_counts.columns = ['city', 'count']\n",
    "    \n",
    "    # 绘图（Pyecharts交互式地图）\n",
    "    map_chart = (\n",
    "        Map()\n",
    "        .add(\"用户数量\", [list(z) for z in zip(city_counts['city'], city_counts['count'])], \"china\")\n",
    "        .set_global_opts(\n",
    "            title_opts=opts.TitleOpts(title=\"用户地域分布\"),\n",
    "            visualmap_opts=opts.VisualMapOpts(\n",
    "                max_=city_counts['count'].max(),\n",
    "                is_calculable=True,\n",
    "                range_color=[\"#F5F6FA\", \"#E0E5F5\", \"#B9C8E8\", \"#7FA2E1\", \"#4274D7\"]\n",
    "            )\n",
    "        )\n",
    "    )\n",
    "    map_chart.render('../visualizations/user_city_distribution.html')\n",
    "    print(\"用户地域分布地图已保存（HTML交互式图表）。\")\n",
    "\n",
    "\n",
    "# ===================== 模板3：商品类别占比饼图 =====================\n",
    "def plot_category_pie():\n",
    "    # 合并订单与商品数据，计算类别销售额\n",
    "    merged = pd.merge(orders_df, products_df, on='product_id')\n",
    "    category_sales = merged.groupby('category')['amount'].sum().reset_index()\n",
    "    \n",
    "    # 绘图（Plotly交互式饼图）\n",
    "    fig = px.pie(\n",
    "        category_sales,\n",
    "        values='amount',\n",
    "        names='category',\n",
    "        title='商品类别销售额占比',\n",
    "        color_discrete_sequence=['#FF6B6B', '#4ECDC4', '#FFD166', '#2A9D8F', '#7209B7']\n",
    "    )\n",
    "    fig.write_image('../visualizations/category_sales_pie.png')\n",
    "    fig.write_html('../visualizations/category_sales_pie.html')\n",
    "    print(\"商品类别占比饼图已保存（PNG+HTML格式）。\")\n",
    "\n",
    "\n",
    "# ===================== 执行所有可视化 =====================\n",
    "if __name__ == \"__main__\":\n",
    "    plot_sales_trend()\n",
    "    plot_user_map()\n",
    "    print(\"所有可视化任务完成！结果已保存至 visualizations 目录。\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f502cbed-328d-4dc6-a61c-fd721075e0d8",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
